%{
#include "functionparser.h"

const char *str;
NOfundef *no;
// Lista de strings para deletar ao final do parsing:
linkedlist listalixo;
// "palavra":
char palavra[STRING_TAMMAX];
// "vars":
char vars[VALORES_TAMANHO+1];//Um espaço a mais para o "\0".
// "funimpl":
funimpl implauxtemp;
funimpl implaux[VALORES_TAMANHO];
unsigned int implaux_indice;
// "funrec_base_impl"
VALORES_TIPO valoraux;
// "funrec_passo_def"
char *funrec_passo_def[2];
// "funnome":
char *funnome_ultimo;

extern int yylex(void);
static void yyerror(const char *s);
%}

// Observação: por padrão, as variáveis do Yacc ($$, $1, $2, etc)
// são inteiras. No nosso caso, elas serão a seguinte union:
%union
{
	char          caractere;
	unsigned int  natural;
	funnome_dados fnome;
}

%token <caractere> LETRA
%token <caractere> VARNOME
%token <natural>   DIGITO
%type  <natural>   numero
%type  <fnome>     funnome

// Símbolo inicial:
%start igualdade

%% /*** *** *** Regras da gramática *** *** ***/

igualdade :
		// *******************************************************************************
		// * ZERO_FUNCTION / SUCCESSOR_FUNCTION / GENERAL_FUNCTION / PROJECTION_FUNCTION *
		// *******************************************************************************
		fundef '=' funimpl
			{
				no->implementacao = implaux_pop();
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("\n[DEBUG] Um \"igualdade ---> fundef '=' funimpl\" foi reconhecido!\n");
					printf("[DEBUG] * no : {");
					fundef_print(no,0);
					printf("}\n");
				#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
				// Verificar se a aridade da função e de sua implementação são iguais:
				if (fundef_aridade(no) != funimpl_aridade(no->implementacao))
				{
					ERRO_ARIDADE_DIFERENTE(no->nome,funimpl_get_nome(no->implementacao),fundef_aridade(no),funimpl_aridade(no->implementacao));
					YYABORT;
				}
				// Verificar se os argumentos da função e de sua implementação são iguais (e se estão na mesma ordem):
				if (strcmp(no->variaveis,funimpl_get_variaveis(no->implementacao)))
				{
					ERRO_ARGUMENTOS_DIFERENTES(no->nome,funimpl_get_nome(no->implementacao));
					YYABORT;
				}
			}
		// *************************
		// * COMPOSITION_OPERATION *
		// *************************
		| fundef '=' funnome '(' internas ')'
			{
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("\n[DEBUG] Um \"igualdade ---> fundef '=' funnome '(' internas ')'\" foi reconhecido!\n");
					printf("[DEBUG] * Definicao:\n");
					printf("[DEBUG]   + nome : {%s}\n",no->nome);
					printf("[DEBUG]   + vars : (");var_print(no->variaveis);printf(")\n");
					printf("[DEBUG] * Funcao externa:\n");
				#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
				// Caso "funnome" seja uma Projeção, verificar se o valor de seu índice "n"
				// é igual a quantidade de funções internas da Composição:
				if (projecao_indice($3,implaux_indice))
				{
					ERRO_COMP_PROJECAO_LIMITE($3.projecao.n,implaux_indice);
					YYABORT;
				}
				var_placeholder();
				implauxtemp = gerar_funimpl($3);
				unsigned int i;
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("[DEBUG] * Funcao(oes) interna(s):\n");
					for (i=0 ; i<implaux_indice ; i++)
					{
						printf("[DEBUG]   + %u. ",i);
						funimpl_print(implaux[i]);
						printf("\n");
					}
				#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
				// Verificações de erros da definição da função em relação a cada função INTERNA da composição:
				for (i=0 ; i<implaux_indice ; i++)
				{
					// Verificar se as aridades são iguais:
					if (fundef_aridade(no) != funimpl_aridade(implaux[i]))
					{
						ERRO_ARIDADE_DIFERENTE(no->nome,funimpl_get_nome(implaux[i]),fundef_aridade(no),funimpl_aridade(implaux[i]));
						YYABORT;
					}
					// Verificar se os argumentos das funções são iguais (e se estão na mesma ordem):
					if (strcmp(no->variaveis,funimpl_get_variaveis(implaux[i])))
					{
						ERRO_ARGUMENTOS_DIFERENTES(no->nome,funimpl_get_nome(implaux[i]));
						YYABORT;
					}
				}
				// Montar a struct da Composição:
				no->implementacao = funimpl_novo_composicao(implauxtemp,implaux,&implaux_indice);
			}
		// ***********************
		// * RECURSION_OPERATION *
		// ***********************
		/// [Recursão: Caso Base]
		| funrec_base_def '=' funrec_base_impl
			{
				implauxtemp = implaux_pop();
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("\n[DEBUG] Um \"igualdade ---> funrec_base_def '=' funrec_base_impl\" foi reconhecido!\n");
					printf("[DEBUG] * nome             : {%s}\n",no->nome);
					printf("[DEBUG] * vars             : (");var_print(no->variaveis);printf(")\n");
					printf("[DEBUG] * funrec_base_impl : {");funimpl_print(implauxtemp);printf("}\n");
				#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
				// --- Caso -----
				// * H(0) = k
				// --------------
				if (fundef_aridade(no) == 1)
				{
					if (implauxtemp.tipo != CONSTANT_FUNCTION)
					{
						ERRO_RECURSAO_CONSTANTE_REQUERIDA(no->nome);
						funimpl_del(implauxtemp);
						YYABORT;
					}
				}
				// --- Caso -------------------------------
				// * H(x1, ..., xn, 0) = F(x1, ..., xn)
				// ----------------------------------------
				else
				{
					if (implauxtemp.tipo == CONSTANT_FUNCTION)
					{
						ERRO_RECURSAO_CONSTANTE_PROIBIDA(no->nome);
						funimpl_del(implauxtemp);
						YYABORT;
					}
					if (fundef_aridade(no) != funimpl_aridade(implauxtemp) + 1)
					{
						ERRO_RECURSAO_ARIDADE_DIFERENTE(funimpl_get_nome(implauxtemp),funimpl_aridade(implauxtemp),no->nome,fundef_aridade(no));
						funimpl_del(implauxtemp);
						YYABORT;
					}
					if (strncmp(no->variaveis,funimpl_get_variaveis(implauxtemp),funimpl_aridade(implauxtemp)))
					{
						ERRO_ARGUMENTOS_DIFERENTES(no->nome,funimpl_get_nome(implauxtemp));
						funimpl_del(implauxtemp);
						YYABORT;
					}
				}
				// Montar a struct da recursão (com o caso base apenas):
				no->implementacao = funimpl_novo_recursao(no,fundef_aridade(no),implauxtemp,RECURSAO_BASE);
			}
		/// [Recursão: Passo]
		| funrec_passo_def '=' funrec_passo_impl
			{
				// --- Casos ------------------------------------------------------
				// * H(x1, ..., xn, t+1) = G(t, H(x1, ..., xn, t), x1, ..., xn)
				// * H(x1, ..., xn, t+1) = G(t, H(t))
				// ----------------------------------------------------------------
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("\n[DEBUG] Um \"igualdade ---> funrec_passo_def '=' funrec_passo_impl\" foi reconhecido!\n");
					printf("[DEBUG] * no : ");
					fundef_print(no,15);
					printf("\n");
				#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
				if (strcmp(funrec_passo_def[0],no->nome))
				{
					ERRO_RECURSAO_NOME_DIFERENTE(funrec_passo_def[0],no->nome);
					YYABORT;
				}
				if (strlen(funrec_passo_def[1]) != fundef_aridade(no))
				{
					ERRO_ARIDADE_DIFERENTE(funrec_passo_def[0],no->nome,strlen(funrec_passo_def[1]),fundef_aridade(no));
					YYABORT;
				}
				if (strcmp(funrec_passo_def[1],no->variaveis))
				{
					ERRO_ARGUMENTOS_DIFERENTES(funrec_passo_def[0],no->nome);
					YYABORT;
				}
			}
		| error
			{ ERRO_SINTAXE; YYABORT; }
		;

// +---------------------------------+
// | RECURSÃO: Caso Base (definição) |
// +---------------------------------+
funrec_base_def :
		palavra '(' varspre DIGITO ')'
			{
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("\n[DEBUG] Um \"funrec_base_def ---> palavra '(' varspre DIGITO ')'\" foi reconhecido!\n");
					printf("[DEBUG] * palavra  : {%s}\n",palavra);
					printf("[DEBUG] * varspre: (");var_print(vars);printf(")\n");
					printf("[DEBUG] * DIGITO   : {%u}\n",$4);
				#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
				if ($4 != 0)
				{
					ERRO_RECURSAO_NAO_ZERO(palavra,0,$4);
					YYABORT;
				}
				// A variável mais a direita (a variável da recursão) desta função será salva como zero (pois este é o CASO BASE).
				// Se uma função idêntica (mas que define o PASSO da recursão) for reconhecida, este zero será trocado pelo
				// nome correto da variável da recursão. Na verdade, a função "montar_recursao()" do arquivo "fileparser.h"
				// unirá o nó BASE e o nó PASSO em um só nó com a definição completa da recursão.
				if (!var_append('0'))
				{
					ERRO_RECURSAO_MAX_ARGUMENTOS(palavra,VALORES_TAMANHO);
					YYABORT;
				}
				// Checar se a definição de função lida é uma das funções primitivas:
				if (funcao_Z_S_GERAL(palavra,vars) != GENERAL_FUNCTION)
				{
					ERRO_FUNCAO_BASICA(palavra);
					YYABORT;
				}
				// Alocar novo nó (sem tipo ainda):
				no = fundef_novo(palavra,vars);
			}
		;

// +-------------------------------------+
// | RECURSÃO: Caso Base (implementação) |
// +-------------------------------------+
funrec_base_impl :
		funimpl
		| valor
			{ implaux_append(funimpl_novo_constante(valoraux)); }
		;

// +-----------------------------+
// | RECURSÃO: Passo (definição) |
// +-----------------------------+
funrec_passo_def :
		palavra '(' vars '+' DIGITO ')'
			{
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("\n[DEBUG] Um \"funrec_passo_def ---> palavra '(' vars '+' DIGITO ')'\" foi reconhecido!\n");
					printf("[DEBUG] * palavra : {%s}\n",palavra);
					printf("[DEBUG] * vars    : (");var_print(vars);printf(")\n");
					printf("[DEBUG] * DIGITO  : {%u}\n",$5);
				#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
				if ($5 != 1)
				{
					ERRO_RECURSAO_NAO_ZERO(palavra,1,$5);
					YYABORT;
				}
				// Checar se a definição de função lida é uma das funções primitivas:
				if (funcao_Z_S_GERAL(palavra,vars) != GENERAL_FUNCTION)
				{
					ERRO_FUNCAO_BASICA(palavra);
					YYABORT;
				}
				setstring(&(funrec_passo_def[0]),palavra);
				setstring(&(funrec_passo_def[1]),vars);
				linkedlist_push_string(&listalixo,funrec_passo_def[0]);
				linkedlist_push_string(&listalixo,funrec_passo_def[1]);
			}
		;

// +---------------------------------+
// | RECURSÃO: Passo (implementação) |
// +---------------------------------+
funrec_passo_impl :
		funnome '(' VARNOME ',' fundef varspos ')'
			{
				// --- Casos ---------------------------------------
				// * (...) = G(t, H(x1, ..., xn, t), x1, ..., xn)
				// * (...) = G(t, H(t))
				// -------------------------------------------------
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("\n[DEBUG] Um \"funrec_passo_impl ---> funnome '(' VARNOME ',' fundef varspos ')'\" foi reconhecido!\n");
					printf("[DEBUG] * Recursao:\n");
					printf("[DEBUG]   + nome : {%s}\n",no->nome);
					printf("[DEBUG]   + vars : (");var_print(no->variaveis);printf(")\n");
					printf("[DEBUG] * Passo (partes):\n");
					printf("[DEBUG]   + nome    : {%s}\n",funnome_ultimo);
					printf("[DEBUG]   + VARNOME : {%c}\n",$3);
					printf("[DEBUG]   + varspos : (");var_print(vars);printf(")\n");
				#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
				// Backup das variáveis da função Passo (da 3ª em diante):
				char *var_backup = NULL;
				setstring(&var_backup,vars);
				linkedlist_push_string(&listalixo,var_backup);
				// Adicionar variável da recursão a lista de variáveis da função Passo (para checar se ela está repetida):
				if (!var_append($3))
				{
					ERRO_ARGUMENTO_DUPLICADO($3,funnome_ultimo);
					YYABORT;
				}
				// Checar se a quantidade de variáveis do função Passo extrapolou o máximo permitido
				// O +1 equivale ao espaço da função H(..) que será argumento para a função G(...):
				if (strlen(vars)+1 > VALORES_TAMANHO)
				{
					ERRO_RECURSAO_MAX_ARGUMENTOS(funnome_ultimo,VALORES_TAMANHO);
					YYABORT;
				}
				// Checar se as variáveis da função Recursao e da função Passo são iguais:
				if (strcmp(no->variaveis,vars))
				{
					ERRO_ARGUMENTOS_DIFERENTES(no->nome,funnome_ultimo);
					YYABORT;
				}
				// Montagem das variáveis da função Passo:
				reset_vars();
				var_append($3);
				var_append(VARS_PLACEHOLDER);
				unsigned int i;
				for (i=0 ; i<strlen(var_backup) ; i++) var_append(var_backup[i]);
				// Verificar se o valor do índice "n" da Projeção é igual a quantidade de variáveis:
				if (projecao_indice($1,strlen(vars)))
				{
					ERRO_PROJECAO_LIMITE_ARIDADE($1.projecao.n,strlen(vars));
					YYABORT;
				}
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("[DEBUG] * Passo (montado):\n");
				#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
				implauxtemp = gerar_funimpl($1);
				// Montar a struct da recursão (com o passo apenas):
				no->implementacao = funimpl_novo_recursao(no,fundef_aridade(no),implauxtemp,RECURSAO_PASSO);
			}
		;

varspre :
		/* VAZIO */
			{ reset_vars(); }
		| vars ','
		;

varspos :
		/* VAZIO */
			{ reset_vars(); }
		| ',' vars
		;

fundef :
		palavra '(' vars ')'
			{
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("\n[DEBUG] Um \"fundef ---> palavra '(' vars ')'\" foi reconhecido!\n");
					printf("[DEBUG] * palavra: {%s}\n",palavra);
					printf("[DEBUG] * vars   : (");var_print(vars);printf(")\n");
				#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
				// Checar se a definição de função lida é uma das funções primitivas:
				if (funcao_Z_S_GERAL(palavra,vars) != GENERAL_FUNCTION)
				{
					ERRO_FUNCAO_BASICA(palavra);
					YYABORT;
				}
				// Alocar novo nó (sem tipo ainda):
				no = fundef_novo(palavra,vars);
				reset_palavra();
			}
		;

// +------------------------------------------+
// | Função Geral, Zero, Sucessor ou Projeção |
// +------------------------------------------+
funimpl :
		funnome '(' vars ')'
			{
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("\n[DEBUG] Um \"funimpl ---> funnome '(' vars ')'\" foi reconhecido!\n");
				#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
				// Verificar se o valor do índice "n" da Projeção é igual a quantidade de variáveis:
				if (projecao_indice($1,strlen(vars)))
				{
					ERRO_PROJECAO_LIMITE_ARIDADE($1.projecao.n,strlen(vars));
					YYABORT;
				}
				implauxtemp = gerar_funimpl($1);
				// Adicionar a implementação lida ao vetor de implementações:
				if (!implaux_append(implauxtemp))
				{
					funimpl_del(implauxtemp);
					ERRO_IMPLEMENTACOES_MAXIMO(VALORES_TAMANHO);
					YYABORT;
				}
			}
		;

internas :
		funimpl
		| internas ',' funimpl
		;

funnome :
		// +--------------------------------+
		// | Função Geral, Zero ou Sucessor |
		// +--------------------------------+
		palavra
			{
				$$.tipo = -1;
				setstring(&($$.nome),palavra);
				linkedlist_push_string(&listalixo,$$.nome);
				funnome_ultimo = $$.nome;
			}
		// +-----------------+
		// | Função Projeção |
		// +-----------------+
		| LETRA '_' numero '_' numero
			{
				// Verificar se o nome da Projeção é "U":
				if ($1 != 'U')
				{
					ERRO_PROJECAO_NOME($1);
					YYABORT;
				}
				if (($3 < 1) || ($3 > $5))
				{
					ERRO_PROJECAO_INDICE($3,$5);
					YYABORT;
				}
				$$.tipo = PROJECTION_FUNCTION;
				// --- Nome da função ------------------------------------------------------------------------
				reset_palavra();
				palavra_append($1);
				palavra_append('_');
				palavra_append_num($3);
				palavra_append('_');
				palavra_append_num($5);
				setstring(&($$.projecao.nome),palavra);
				// Guardar referência‎ para desalocação futura:
				linkedlist_push_string(&listalixo,$$.projecao.nome);
				funnome_ultimo = $$.projecao.nome;
				// -------------------------------------------------------------------------------------------
				$$.projecao.i = $3;
				$$.projecao.n = $5;
			}
		;

palavra :
		LETRA
			{ reset_palavra(); palavra_append($1); }
		| palavra LETRA
			{ palavra_append($2); }
		;

vars :
		VARNOME
			{ reset_vars(); var_append($1); }
		| vars ',' VARNOME
			{
				if (!var_append($3))
				{
					if (strlen(palavra))
						ERRO_ARGUMENTO_DUPLICADO($3,palavra);
					else
						ERRO_ARGUMENTO_DUPLICADO($3,funnome_ultimo);
					YYABORT;
				}
			}
		;

numero :
		DIGITO
			{ $$ = $1; }
		| numero DIGITO
			{ $$ = $1 * 10 + $2; }
		;

valor :
		DIGITO
			{ valoraux = $1; }
		| valor DIGITO
			{ valoraux = valoraux * 10 + $2; }
		;

%% /*** *** *** Funções do parser *** *** ***/

// --- "palavra" --------------------------------------------------------
void reset_palavra(void)
{
	palavra[0] = '\0';
}

void palavra_append(char c)
{
	unsigned int n = strlen(palavra);
	if (n >= STRING_TAMMAX) return;
	palavra[n] = c;
	palavra[n+1] = '\0';
}

void palavra_append_num(unsigned int n)
{
	if ((n/10) != 0) palavra_append_num(n/10);
	palavra_append((n%10)+'0');
}

// --- "vars" -----------------------------------------------------------
void reset_vars(void)
{
	vars[0] = '\0';
}

bool var_append(char c)
{
	// Verifica se a variável "c" já está no conjunto.
	// Ou seja: checa se ela já está "declarada"!
    if (strchr(vars,c)) return(false);
    unsigned int n = strlen(vars);
    if (n >= VALORES_TAMANHO) return (false);
    vars[n] = c;
    vars[n+1] = '\0';
    return(true);
}

void var_placeholder(void)
{
	if (implaux_indice > VALORES_TAMANHO) return;
	unsigned int i=0;
	while (i < implaux_indice) vars[i++] = VARS_PLACEHOLDER;
	vars[i] = '\0';
}

// --- "funimpl" --------------------------------------------------------
bool implaux_append(funimpl fi)
{
	// Checar se extrapolou o número máximo de implementações:
	if (implaux_indice >= VALORES_TAMANHO) return(false);
	implaux[implaux_indice] = fi;
	implaux_indice++;
	return(true);
}

funimpl implaux_pop(void)
{
	funimpl fi;
	fi.tipo = -1;
	fi.impl = NULL;
	if (implaux_indice)
	{
		fi = implaux[implaux_indice-1];
		implaux_indice--;
	}
	return(fi);
}

void implaux_clear(void)
{
	unsigned int i;
	for (i=0 ; i<implaux_indice ; i++)
		funimpl_del(implaux[i]);
	implaux_indice = 0;
}

// Checar se a função PR representada pelo nome "n" e pelo array de variáveis "v"
// é uma das primitivas "Z" ou "S" ou uma Função Geral:
funtipo funcao_Z_S_GERAL(const char *n, const char *v)
{
	if (!n || !v) return(-1);
	if (!strcmp(n,"Z") && (strlen(v) == 1)) return(ZERO_FUNCTION);
	if (!strcmp(n,"S") && (strlen(v) == 1)) return(SUCCESSOR_FUNCTION);
	return(GENERAL_FUNCTION);
}

// --- "funnome" --------------------------------------------------------
funimpl gerar_funimpl(funnome_dados fn)
{
	if (fn.tipo == PROJECTION_FUNCTION)
	{
		#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
			printf("[DEBUG]   + nome: {%s}\n",fn.projecao.nome);
			printf("[DEBUG]   + i   : {%u}\n",fn.projecao.i);
			printf("[DEBUG]   + n   : {%u}\n",fn.projecao.n);
			printf("[DEBUG]   + vars: (");var_print(vars);printf(")\n");
		#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
		return(funimpl_novo_projecao(fn.projecao.nome,vars,fn.projecao.i));
	}
	else
	{
		#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
			printf("[DEBUG]   + nome: {%s}\n",fn.nome);
			printf("[DEBUG]   + vars: (");var_print(vars);printf(")\n");
		#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
		return(funimpl_novo(funcao_Z_S_GERAL(fn.nome,vars),fn.nome,vars));
	}
}

bool projecao_indice(funnome_dados fn, unsigned int a)
{
	if ((fn.tipo == PROJECTION_FUNCTION) && (fn.projecao.n != a)) return(true);
	return(false);
}

// --- Funções básicas do Yacc ------------------------------------------
NOfundef* analisar(const char *s)
{
	str = s;
	no = NULL;
	linkedlist_init(&listalixo,NO_STRING);
	reset_palavra();
	reset_vars();
	implauxtemp.tipo = -1;
	implauxtemp.impl = NULL;
	implaux_indice = 0;
	valoraux = 0;
	funrec_passo_def[0] = NULL;
	funrec_passo_def[1] = NULL;
	funnome_ultimo = NULL;
	#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
		printf("\n[DEBUG] *** *** *** \"yyparse()\" : INICIO *** *** ***\n");
	#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
	// Se ocorrer algum erro no parsing...
	if (yyparse())
	{
		// Desalocar o "no" e setá-lo para NULL:
		fundef_del(no);
		no = NULL;
		// Desalocar quaisquer elementos no vetor de implementações:
		implaux_clear();
	}
	#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
		printf("[DEBUG] Lista de strings temporarias:\n");
		llno *p = listalixo.inicio;
		while(p)
		{
			printf("[DEBUG] * \"%s\"\n",p->valor.s);
			p = p->prox;
		}
	#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
	// Desalocar lista de strings temporárias:
	linkedlist_clear(&listalixo);
	#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
		printf("\n[DEBUG] *** *** *** \"yyparse()\" : FIM *** *** ***\n");
	#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
	return(no);
}

static void yyerror(const char *s)
{
	//fprintf(stderr, "%s\n", s);
}

int yylex(void)
{
	int c = *str;
	// Checar se o caractere lido é um dos caracteres extras para o nome de função:
	bool is_extra = false;
	if ((*str != '\0') && strchr(FUNNOME_CARACTERES_EXTRAS,*str)) is_extra = true;
	// Incrementar o ponteiro da string de entrada (se o caractere atual NÃO for um '\0'):
	if (*str) str++;
	// Se for uma letra maiúscula:
	if ((isalpha(c) && isupper(c)) || is_extra)
	{
		yylval.caractere = c;
		return(LETRA);
	}
	// Se for uma letra minúscula:
	if (isalpha(c) && islower(c))
	{
		yylval.caractere = c;
		return(VARNOME);
	}
	// Se for um dígito:
	if (isdigit(c))
	{
		yylval.natural = c - '0';
		return(DIGITO);
	}
	return(c);
}
